use std::sync::{
    atomic::{AtomicUsize, Ordering},
    Arc,
};

use dfs::{
    dfs_read, dfs_write,
    inode::{inode_root, FileCreateOptions, InodeOperation},
    DfsError, DfsOpenOptions, DfsResult,
};

struct TestFile {
    data1: AtomicUsize,
}

impl InodeOperation for TestFile {
    fn read(
        &self,
        _: &mut Box<dyn std::any::Any + Send>,
        buf: &mut String,
        pos: &mut u64,
    ) -> DfsResult<usize> {
        let str = self.data1.load(Ordering::Relaxed).to_string();
        let size = str.len();
        *pos += size as u64;
        *buf = str;
        Ok(size)
    }

    fn write(
        &self,
        _: &mut Box<dyn std::any::Any + Send>,
        buf: &str,
        pos: &mut u64,
    ) -> DfsResult<usize> {
        let data1 = buf.parse::<usize>().map_err(|_| DfsError::InvalidArgs)?;
        *pos = data1 as u64;
        self.data1.store(data1, Ordering::Relaxed);
        Ok(buf.len())
    }

    fn size(&self) -> usize {
        self.data1.load(Ordering::Relaxed).to_string().len()
    }
}

#[test]
fn file_create() {
    let data1 = Arc::new(TestFile { data1: AtomicUsize::new(2) });
    let _ = FileCreateOptions::new()
        .name("test1")
        .read_write(true)
        .seek(true)
        .create_file(inode_root(), data1.clone())
        .unwrap();
    let mut buf = String::new();
    let data = dfs_read("/test1", &mut buf).unwrap();
    assert_eq!(data, 1);
    assert_eq!("2", buf.as_str());

    dfs_write("/test1", "3").unwrap();
    let data = dfs_read("/test1", &mut buf).unwrap();
    assert_eq!(data, 1);
    assert_eq!("3", buf.as_str());

    {
        let file = DfsOpenOptions::new().read(true).open("/test1");
        assert_eq!(inode_root().remove_file("test1").err().unwrap(), DfsError::BusyInode);
        let fd = file.ok().unwrap();
        {
            let data = fd.read(&mut buf).unwrap();
            assert_eq!(data, 1);
            assert_eq!("3", buf.as_str());
        }
        data1.data1.store(5, Ordering::Relaxed);
        let data = fd.read(&mut buf).unwrap();
        assert_eq!(data, 1);
        assert_eq!("5", buf.as_str());
    }
    inode_root().remove_file("test1").unwrap();
}
